﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BLL;
using Logic.SocialNetworks;
using log4net;
using System.Data;
using BO;

namespace Logic.BusinessLogic
{
	public class Stats
	{

		public static BO.TracedAccount CrateNewTrace(int accountID, BO.TracedAccount.AccountTypes type, string name)
		{
			var trace = new BO.TracedAccount
			{
				AccountID = accountID,
				AccountType = type,
				Name = name,
				StatusEnum = (int)EntityStatuses.Active,
				StartDate = DateTime.Now
			};

			switch (type)
			{
				case BO.TracedAccount.AccountTypes.Facebook:
					{
						var page = Social.Facebook.GraphApi.GetPageByName(name);
						if (page.ResultOption == Social.ServiceResultOptions.Success)
						{
							trace.FbPageID = page.Content.id;
							trace.FbPageUrl = page.Content.link;
						}
					}
					break;
				case BO.TracedAccount.AccountTypes.Twitter:
					break;
				default:
					break;
			}

			trace.Insert();
			return trace;
		}

		public static List<BO.PostStat> GetPostDailyStats(long postID)
		{
			return GetPostDailyStats(postID, null);
		}

		public static List<BO.PostStat> GetPostDailyStats(long postID, DateTime? since)
		{
			var q = BLL.PostStats.Get()
						.Where(BLL.PostStats.Columns.PostID, Actions.Equal, postID);

			if (since.HasValue)
				q.Where(PostStats.Columns.Date, Actions.BiggerThanOrEqual, since.Value);

			return q.Select();
		}

		public static List<BO.Post> GetPostsByAccountID(int accountID, BO.Post.PostTypes? postType = null, int? count = null)
		{
			var q = BLL.Posts.Get()
									.Where(Posts.Columns.AccountID, Actions.Equal, accountID)
									.Where(Posts.Columns.StatusEnum, Actions.Equal, BLL.EntityStatuses.Active)
									.OrderBy(Posts.Columns.TimePosted, true);
			if(count.HasValue)
				q.Limit(0, count.Value);
									//.Where(Posts.Columns.StatusEnum, Actions.Equal, (int)BLL.EntityStatuses.Active)
			if (postType != null)
				q.Where(Posts.Columns.EnumPostType, Actions.Equal, (int)postType.Value);

			return q.Select();
		}

		public static List<BO.Post> GetPostsOfMasterAccount(int mAccountID, BO.Post.PostTypes? postType = null, int count = 5)
		{
			DataTable dt = DataAccess.Stats.GetPostsOfMasterAccount(mAccountID, postType, count);

			var result = new List<BO.Post>();
			foreach (DataRow dr in dt.Rows)
				result.Add(new BO.Post(dr));
			return result;
		}


		public static List<BO.Post> GetPostsByProfileAccountID(int profileID, BO.Post.PostTypes? postType = null, int count = 5)
		{
			DataTable dt = DataAccess.Stats.GetPostsOfProfile(profileID, postType, count);
			var result = new List<BO.Post>();
			foreach (DataRow dr in dt.Rows)
				result.Add(new BO.Post(dr));
			return result;
		}


		public static List<BO.TracedAccount> GetTrackedPages(int accountID)
		{
			var pages = BLL.TracedAccounts.Get()
											.Where(TracedAccounts.Columns.AccountID, Actions.Equal, accountID)
											.Where(TracedAccounts.Columns.StatusEnum, Actions.Equal, BLL.EntityStatuses.Active)
											.Join(TraceStats.Get(), BLL.TraceStats.Columns.TraceAccountID)
											.Select();

			return pages;
		}

		public static void RemoveTrack(int trackID, int? currentUsrID)
		{
			if (!currentUsrID.HasValue)
				return;

			var track = BLL.TracedAccounts.GetByID(trackID);
			track.EntityStatus = EntityStatuses.Deleted;
			track.Update();

		}

		public static List<BO.Account> GetAllActiveTraces()
		{
			return BLL.Accounts.Get()
								.Where(BLL.Accounts.Columns.StatusEnum, Actions.Equal, BLL.EntityStatuses.Active)
								.Join(BLL.TracedAccounts.Get()
										.Where(TracedAccounts.Columns.StatusEnum, Actions.Equal, BLL.EntityStatuses.Active),
										BLL.TracedAccounts.Columns.AccountID)
										.Select();
		}

		public static BO.TraceStat GetTodaysTraceStat(int traceID)
		{
			var stat = BLL.TraceStats.Get()
										.Where(TraceStats.Columns.TraceAccountID, Actions.Equal, traceID)
										.Where(TraceStats.Columns.Date, Actions.Equal, DateTime.Today)
										.SelectOne();

			if (stat == null)
				stat = CrateNewTraceStat(traceID);

			return stat;
		}

		private static BO.TraceStat CrateNewTraceStat(int traceID)
		{
			var stat = new BO.TraceStat { Date = DateTime.Today, TraceAccountID = traceID };
			stat.Insert();
			return stat;
		}

		public static void UpdateAccountsStats(Social.Twitter.ITwitterConfig twConfig)
		{
			ILog logger = LogManager.GetLogger("UpdateAccountsStats");
			if (logger.IsDebugEnabled)
				logger.Debug("Update Accounts process start");

			var accounts = BLL.Accounts.Get().Where(BLL.Accounts.Columns.StatusEnum, Actions.Equal, BLL.EntityStatuses.Active).Select();

			foreach (var account in accounts)
			{
				var tracker = new StateUpdater(account, twConfig);
				tracker.UpdateAccountStats();
			}

			if (logger.IsDebugEnabled)
				logger.Debug("Update Accounts process end");
		}

		public static void UpdateTracedAccountsStats(Social.Twitter.ITwitterConfig twConfig)
		{
			ILog logger = LogManager.GetLogger("UpdateTracedAccountsStats");
			if (logger.IsDebugEnabled)
				logger.Debug("Update Traced accounts process start");

			var accounts = Logic.BusinessLogic.Stats.GetAllActiveTraces();
			foreach (var account in accounts)
			{
				var tracker = new StateUpdater(account, twConfig);
				tracker.Track();
			}

			if (logger.IsDebugEnabled)
				logger.Debug("Update Traced accounts process end");

		}

		public static void UpdatePostStats(Social.Twitter.ITwitterConfig twConfig)
		{
			ILog logger = LogManager.GetLogger("UpdatePostStats");
			if (logger.IsDebugEnabled)
				logger.Debug("Update posts process start");

			var accounts = GetAllAccountsWithPosts();
			foreach (var account in accounts)
			{
				PostTracker tracker = new PostTracker(account, twConfig);
				tracker.UpdatePoststStats();
			}

		}

		private static List<BO.Account> GetAllAccountsWithPosts()
		{
			return
			BLL.Accounts.Get()
						.Where(Accounts.Columns.StatusEnum, Actions.Equal, EntityStatuses.Active)
						.Join(Posts.Get().Where(Posts.Columns.StatusEnum, Actions.NotEqual, EntityStatuses.Deleted)
								, Posts.Columns.AccountID)
						.Select();

		}

		public static List<BO.TraceStat> GetTraceDailyStats(long traceID, DateTime? since)
		{
			var q = BLL.TraceStats.Get()
							.Where(TraceStats.Columns.TraceAccountID, Actions.Equal, traceID);

			if (since.HasValue)
				q.Where(TraceStats.Columns.Date, Actions.BiggerThanOrEqual, since.Value);
			return q.Select();
		}

		public static List<BO.AccountStat> GetAccountDailyStats(long accountID, DateTime? since = null)
		{
			var q = BLL.AccountStats.Get()
									.Where(AccountStats.Columns.AccountID, Actions.Equal, accountID)
									.OrderBy(AccountStats.Columns.Date, false);

			if (since.HasValue)
				q.Where(AccountStats.Columns.Date, Actions.BiggerThanOrEqual, since.Value);
			return q.Select();
		}

		public static List<BO.AccountStat> GetMasterAccountDailyStats(int accountID, DateTime? since = null)
		{
			var dt = DataAccess.Stats.GetMaterAccountDailyStats(accountID, since);

			var result = new List<BO.AccountStat>();
			
			foreach (DataRow dr in dt.Rows)
			{
				result.Add(
					new BO.AccountStat
					{ 
						TwFollowersNum = Convert.ToInt32(dr["TwFollowersNum"]),
						FbPageFanNum = Convert.ToInt32(dr["FbPageFanNum"]), 
						FbFriendsNum = Convert.ToInt32(dr["FbFriendsNum"]) ,
						Date = Convert.ToDateTime(dr["Date"])
					});
			}

			return result;
		}
		
		public static List<MasterAccount> GetMasterAcountsOverview(int profileID)
		{
			var mAccounts = AccountService.GetMasterAccountsForProfile(profileID);
			foreach (MasterAccount master in mAccounts)
			{
				master.OverView = GetMasterAcountOverview(master.ID);
			}

			return mAccounts;
		}
		public static MasterAccount GetMasterAccountWithOverview(int masterAccountID)
		{
			var master = BLL.MasterAccounts.GetByID(masterAccountID);
			master.OverView = GetMasterAcountOverview(masterAccountID);
			return master;
		}
		public static AccountOverview GetMasterAcountOverview(int masterAccountID)
		{			
			var res = new AccountOverview();
			var accounts = AccountService.GetAccountsByMasterID(masterAccountID);
			foreach (var account in accounts)
			{
				res.FbFanCount += account.FbPageFanNum;
				res.TwFollowerCount += account.TwFollowersNum;
				var postsOver = GetPostsOverview(account.ID);
				res.TotalPostCount += postsOver.TotalPostCount;
				res.TwPostCount += postsOver.TwPostCount;
				res.TwReplyCount += postsOver.TwReplyCount;
				res.TwRetweetCount += postsOver.TwRetweetCount;
				res.FbPostCount += postsOver.FbPostCount;
				res.FbCommentCount += postsOver.FbCommentCount;
			}

			return res;
		}

		public static List<BO.Account> GetAccountsOverview(int masterAccountID)
		{
			var accounts = AccountService.GetAccountsByMasterID(masterAccountID);
			foreach (var account in accounts)
			{
				account.OverView = GetPostsOverview(account.ID);
			}

			return accounts;
		}

		internal static BO.AccountStat GetTodaysAccountStat(int accountID)
		{
			var stat = BLL.AccountStats.Get()
										.Where(AccountStats.Columns.AccountID, Actions.Equal, accountID)
										.Where(AccountStats.Columns.Date, Actions.Equal, DateTime.Today)
										.SelectOne();

			if (stat == null)
				stat = CrateNewAccountStat(accountID);

			return stat;
		}

		private static BO.AccountStat CrateNewAccountStat(int accountID)
		{
			var stat = new BO.AccountStat { Date = DateTime.Today, AccountID = accountID };
			stat.Insert();
			return stat;
		}

		public static AccountOverview GetPostsOverview(int accountID)
		{
			var posts = GetPostsByAccountID(accountID);
			return new AccountOverview(posts);
		}

		internal static BO.PostStat GetTodaysPostStat(long postID)
		{
			var stat = PostStats.Get()
									.Where(PostStats.Columns.PostID, Actions.Equal, postID)
									.Where(PostStats.Columns.Date, Actions.Equal, DateTime.Today)
									.SelectOne();
			if (stat == null)
				stat = CrateNewPostStat(postID);

			return stat;
		}

		private static BO.PostStat CrateNewPostStat(long postID)
		{
			var stat = new BO.PostStat { PostID = postID, Date = DateTime.Today, EntityStatus = EntityStatuses.Active };
			stat.Insert();
			return stat;
		}



		
	}

	
}
